自己动手写编译器:while,for,do等循环语句的中间代码生成 您所在的位置:网站首页 编译原理 代码生成 自己动手写编译器:while,for,do等循环语句的中间代码生成

自己动手写编译器:while,for,do等循环语句的中间代码生成

2024-07-04 22:54| 来源: 网络整理| 查看: 265

我们的简易编译器完成了一大部分,但还有一些关键的语法结构没有处理,那就是for, while, do…while等循环语句对应的中间代码还没有生成,本节我们就针对这些语法结构进行相应的中间代码生成。

首先我们要了解循环语句对应的语法表达式:

stmt -> "while" "( " bool ")" stmts stmt -> "do" stmts "while" "(" bool ")" ";" stmt-> "break"

为了简单起见,我们暂时不处理for循环,有兴趣的同学可以自己添加试试。下面我们先创建while, do…while语法结构对应的语法树节,在inter文件夹中创建while.go,然后添加代码如下:

package inter import ( "errors" "fmt" ) type While struct { stmt *Stmt //继承自Stmt节点 expr ExprInterface //对应while 后面的条件判断表达式 while_stmt StmtInterface //对应while的循环体部分 } func NewWhile(line uint32, expr ExprInterface, while_stmt StmtInterface) *While { if expr.Type().Lexeme != "bool" { //用于while后面的表达式必须为bool类型 err := errors.New("bool type required for while") panic(err) } return &While{ stmt: NewStmt(line), expr: expr, while_stmt: while_stmt, } } //下面仅仅是调用其父类接口 func (w *While) Errors(str string) error { return w.stmt.Errors(str) } func (w *While) NewLabel() uint32 { return w.stmt.NewLabel() } func (w *While) EmitLabel(label uint32) { w.stmt.EmitLabel(label) } func (w *While) Emit(code string) { w.stmt.Emit(code) } func (w *While) Gen(start uint32, end uint32) { w.expr.Jumping(0, end) label := w.NewLabel() w.EmitLabel(label) w.while_stmt.Gen(label, start) //生成while循环体语句的起始标志 emit_code := fmt.Sprintf("goto L%d", start) w.Emit(emit_code) }

上面代码中需要注意的就是Gen函数,首先它创建跳转标签,注意这些标签对循环的正确执行有着非常重要的作用,然后它先对while后面的判断表达式生成代码,然后对while循环体内的语句集合生成代码,具体的逻辑讲解请参看b站搜索Coding迪斯尼参看我的调试演示。

接下来我们要做的是修改语法解析代码,在list_parser.go中修改stmt解析函数如下:

func (s *SimpleParser) stmt() inter.StmtInterface { /* if "(" bool ")" if -> "(" bool ")" ELSE "{" stmt "}" bool -> bool "||"" join | join join -> join "&&" equality | equality equality -> equality "==" rel | equality != rel | rel rel -> expr < expr | expr = expr | expr > expr | expr rel : a > b , a < b, a d || e < f */ switch s.cur_tok.Tag { case lexer.IF: s.move_forward() err := s.matchLexeme("(") if err != nil { panic(err) } s.move_forward() x := s.bool() err = s.matchLexeme(")") if err != nil { panic(err) } s.move_forward() //越过 ) s.move_forward() //越过{ s1 := s.stmt() err = s.matchLexeme("}") if err != nil { panic(err) } s.move_forward() //越过} //判断if 后面是否跟着else if s.cur_tok.Tag != lexer.ELSE { return inter.NewIf(s.lexer.Line, x, s1) } else { s.move_forward() //越过else关键字 err = s.matchLexeme("{") if err != nil { panic(err) } s.move_forward() //越过{ s2 := s.stmt() //else 里面包含的代码块 err = s.matchLexeme("}") if err != nil { panic(err) } return inter.NewElse(s.lexer.Line, x, s1, s2) } case lexer.WHILE: s.move_forward() //while 后面跟着左括号, 然后是判断表达式,以右括号结尾 err := s.matchLexeme("(") if err != nil { panic(err) } s.move_forward() while_bool := s.bool() err = s.matchLexeme(")") if err != nil { panic(err) } s.move_forward() //越过 ) s.move_forward() //越过{ //解析while循环成立时要执行的语句块 while_stmt := s.stmts() err = s.matchLexeme("}") if err != nil { panic(err) } s.move_forward() //越过} return inter.NewWhile(s.lexer.Line, while_bool, while_stmt) default: return s.expression() } }

这里我们增加了对while关键字的判断,然后执行其对应的语法解析逻辑,完成上面代码后,我们在main.go中实现包含while语句的代码,这样就能运行上面代码并查看结果:

func main() { source := `{int a; int b; int c; a = 3; b = 0; while (a >= 0 && b = 0 , b =0和b = 0 && b = 0 && b =0 成立,那么再判断b


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有